package gee

import (
	"log"
	"net/http"
	"strings"
)

// router 路由
type router struct {
	roots    map[string]*node       // trie前缀匹配路由数，key为method
	handlers map[string]HandlerFunc // 存储处理函数和路由的对应关系
}

// newRouter 获取router实例
func newRouter() *router {
	return &router{
		roots:    make(map[string]*node),
		handlers: make(map[string]HandlerFunc),
	}
}

// parsePattern 解析路径，拆分为part slice
func parsePattern(pattern string) []string {
	vs := strings.Split(pattern, "/")

	parts := make([]string, 0)
	for _, item := range vs {
		if item != "" {
			parts = append(parts, item)
			if item[0] == '*' {
				break
			}
		}
	}

	return parts
}

// addRouter 添加路由
func (r *router) addRouter(method string, pattern string, handler HandlerFunc) {
	log.Printf("Route %4s - %s", method, pattern)
	parts := parsePattern(pattern)

	key := method + "-" + pattern

	if _, ok := r.roots[method]; !ok {
		r.roots[method] = &node{}
	}

	// 插入pattern的节点
	r.roots[method].insert(pattern, parts, 0)
	// 插入路由对应的处理方法
	r.handlers[key] = handler
}

// getRouter 获取路由
func (r *router) getRouter(method string, pattern string) (*node, map[string]string) {
	searchParts := parsePattern(pattern)
	params := make(map[string]string)

	// 获取对应方法下的路由数
	root, ok := r.roots[method]
	if !ok {
		return nil, nil
	}

	// 搜索路由数中的节点
	n := root.search(searchParts, 0)
	if n == nil {
		return nil, nil
	}

	parts := parsePattern(n.pattern)
	for index, part := range parts {
		// 如果子路径是任意匹配符号
		if part[0] == ':' {
			// 设置任意匹配的匹配关系
			params[part[1:]] = searchParts[index]
		}

		// 如果子路径是通配符，同时子路径长度大于1
		if part[0] == '*' && len(part) > 1 {
			// 设置通配符的匹配关系
			params[part[1:]] = strings.Join(searchParts[index:], "/")
			break
		}
	}

	return n, params
}

// handle 路由处理
func (r *router) handle(c *Context) {
	n, params := r.getRouter(c.Method, c.Path)
	if n != nil {
		c.Params = params
		key := c.Method + "-" + n.pattern
		c.handlers = append(c.handlers, r.handlers[key]) // 将路由的处理函数加入到上下文中
	} else {
		c.handlers = append(c.handlers, func(c *Context) {
			c.String(http.StatusNotFound, "404 NOT FOUND: %s\n", c.Path)
		})
	}
	// 继续向下迭代
	c.Next()
}
